#include "nodecollector.h"

#include <Poco/Random.h>
#include <Poco/StringTokenizer.h>
using Poco::Random;
using Poco::StringTokenizer;

#include <Poco/Net/DNS.h>
#include <Poco/Net/IPAddress.h>
using Poco::Net::IPAddress;

#include "command/node/sendinfocommand.h"
using namespace Commands;

#include <cstring>
#include <sstream>
using namespace std;

NodeCollector::NodeCollector(SocketAddress group, string ringname)
	: _group(group)
	  , _ringname(ringname)
	  , _lock(new Semaphore(0,1))
	  , _isset(false)
	  , _stopping(false)
{
	_recv.bind(SocketAddress(Poco::Net::DNS::thisHost().addresses().front(), 0));
	_recv.setReceiveTimeout(Poco::Timespan(1,0));
	_mcast.bind(SocketAddress(IPAddress(),_group.port()),true);
	_mcast.joinGroup(_group.host());
	_mcast.setLoopback(false);
}

NodeCollector::~NodeCollector()
{
	delete _lock;
}

SocketAddress NodeCollector::node()
{
	if (!_isset)
		_lock->wait();
	return _nodeAddr;
}

#define MAX_LEN 1500
void NodeCollector::run()
{
	SendInfoCommand cmd(_recv.address());

	string r = cmd.repr();
	_mcast.sendTo(r.c_str(), r.size(), _group);

	while(!_stopping){
		char buffer[MAX_LEN];
		memset(buffer, 0, MAX_LEN);
		SocketAddress sender;
		int len = 0;
		try {
			len = _recv.receiveFrom( buffer, MAX_LEN, sender );

			StringTokenizer st(buffer, ":", StringTokenizer::TOK_IGNORE_EMPTY);
			UInt16 rec_port;
			{
				cout << "NodeCollector :: Reading port" << endl;
				istringstream (st[1]) >> rec_port;
			}

			cout << "NodeCollector :: Received " << len << " :: \"" << rec_port << "\" from " << sender.toString() << endl;
			SocketAddress nodeAddr(sender.host(), rec_port);
			cout << "NodeCollector :: Adding " << nodeAddr.toString() << endl;
			_nodes.push_back(nodeAddr);
		} catch (...) {
			cout << "NodeCollector :: Not Receiving Anything" << endl;
			_stopping = true;
			_recv.close();
		}
	}

	Random rand;
	rand.seed();
	int i = rand.nextFloat() * _nodes.size();
	_nodeAddr = _nodes[i];
	_isset = true;
	_lock->set();
}
#undef MAX_LEN
